home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 5817 / 5817.xpi / chrome / content / udf.js < prev    next >
Text File  |  2010-02-11  |  19KB  |  529 lines

  1. Components.utils.import("resource://sqlitemanager/fileIO.js");
  2.  
  3. //var Database;
  4. var SmUdf = {
  5.   dbFunc: null,
  6.  
  7.   init: function() {
  8.     try {
  9.       //open connection to udf db
  10.       if (this.dbFunc == null)
  11.         this.dbFunc = new SQLiteHandler();
  12.  
  13.       var fUserFile = this.getUserFile();
  14.       var bConnected = false;
  15.       if (fUserFile != null)
  16.         bConnected = this.dbFunc.openDatabase(fUserFile);
  17.  
  18.       if (bConnected) {
  19.         //if connected & if tables do not exist, create them and insert example rows
  20.         if (!this.dbFunc.tableExists('functions')) {
  21.           var aQ = this.getFuncQueries();
  22.           this.dbFunc.executeTransaction(aQ);
  23.         }
  24.         if (!this.dbFunc.tableExists('aggregateFunctions')) {
  25.           var aQ = this.getAggFuncQueries();
  26.           this.dbFunc.executeTransaction(aQ);
  27.         }
  28.         return true;
  29.       }
  30.     } catch (e) {
  31.       Components.utils.reportError('Failed to open a connection to UDF database\n' + (fUserFile != null)?'db: user selected':'db: supplied');
  32.     }
  33.  
  34.     this.dbFunc = null;
  35.     return false;
  36.   },
  37.  
  38.   getFuncQueries: function() {
  39.     var aSql = [];
  40.     aSql.push('DROP TABLE IF EXISTS "functions";');
  41.     aSql.push('CREATE TABLE "functions" ("name" TEXT PRIMARY KEY  NOT NULL, "body" TEXT NOT NULL, "argLength" INTEGER, "aggregate" INTEGER NOT NULL  DEFAULT 0, "enabled" INTEGER NOT NULL  DEFAULT 1, "extraInfo" TEXT);');
  42.     aSql.push('INSERT INTO "functions" VALUES("regexp",\'var regExp = new RegExp(aValues.getString(0));\nvar strVal = new String(aValues.getString(1));\n\nif (strVal.match(regExp)) return 1;\nelse return 0;\',2,0,1,NULL);');
  43.     aSql.push('INSERT INTO "functions" VALUES("addAll","var sum = 0;\nfor (var j = 0; j < aValues.numEntries; j++) {\n  sum += aValues.getInt32(j);\n}\nreturn sum;",-1,0,1,NULL);');
  44.     aSql.push('INSERT INTO "functions" VALUES("joinValues","var valArr = [];\n\nfor (var j = 0; j < aValues.numEntries; j++) {\n  switch (aValues.getTypeOfIndex(j)) {\n    case 0: //NULL\n      valArr.push(null);\n      break;\n    case 1: //INTEGER\n      valArr.push(aValues.getInt64(j));\n      break;\n    case 2: //FLOAT\n      valArr.push(aValues.getDouble(j));\n      break;\n    case 3: //TEXT\n      default:\n      valArr.push(aValues.getString(j));\n  }\n}\nreturn valArr.join(\',\');",-1,0,1,NULL);');
  45.     return aSql;
  46.   },
  47.  
  48.   getAggFuncQueries: function() {
  49.     var aSql = [];
  50.     aSql.push('DROP TABLE IF EXISTS "aggregateFunctions";');
  51.     aSql.push('CREATE TABLE "aggregateFunctions" ("name" TEXT PRIMARY KEY  NOT NULL, "argLength" INTEGER, "onStepBody" TEXT, "onFinalBody" TEXT, "enabled" INTEGER NOT NULL DEFAULT 1, "extraInfo" TEXT);');
  52.     aSql.push('INSERT INTO "aggregateFunctions" ("name", "argLength", "onStepBody", "onFinalBody", "enabled", "extraInfo") VALUES("stdDev", 1, "this._store.push(aValues.getInt32(0));", "var iLength = this._store.length;\nlet total = 0;\nthis._store.forEach(function(elt) { total += elt });\nlet mean = total / iLength;\nlet data = this._store.map(function(elt) {\n  let value = elt - mean;\n  return value * value;\n});\ntotal = 0;\ndata.forEach(function(elt) { total += elt });\nthis._store = [];\nreturn Math.sqrt(total / iLength);",1,NULL);');
  53.     return aSql;
  54.   },
  55.  
  56.   close: function() {
  57.     //close connection to udf db
  58.     try {
  59.       if (this.dbFunc != null)
  60.         this.dbFunc.closeConnection();
  61.     } catch (e) {
  62.       sm_log('Failed to close the connection to UDF database');
  63.       this.dbFunc = null;
  64.       return false;
  65.     }
  66.  
  67.     return true;
  68.   },
  69.   
  70.   loadTab: function() {
  71.     //connect to udf db
  72.     this.init();
  73.  
  74.     //get udfDbDirPath from prefs
  75.     $$("udfDbDirPath").value = sm_prefsBranch.getCharPref("udfDbDirPath");
  76.  
  77.     //populate menulist with all function names
  78.     this.populateFuncMenuList(false);
  79.     this.populateFuncMenuList(true);
  80.   },
  81.  
  82.   selectUdfDir: function() {
  83.     //select a dir
  84.     var dir = SmGlobals.chooseDirectory("Choose location of user-defined functions database (smFunctions.sqlite)...");
  85.     if (dir == null) {
  86.       alert("Please choose a directory before proceeding.\nIf you already have smFunctions.sqlite file, then choose the directory where it is located.\nIf you do NOT have an existing smFunctions.sqlite file, then one will be created in the directory you choose.\nThe chosen location should have read/write permissions.");
  87.     }
  88.     else {
  89.       sm_prefsBranch.setCharPref("udfDbDirPath", dir.path);
  90.       //reload this tab
  91.       this.loadTab();
  92.     }
  93.   },
  94.  
  95.   getUserFile: function() {
  96.     var udfDbDirPath = sm_prefsBranch.getCharPref("udfDbDirPath");
  97.     if (udfDbDirPath == null || udfDbDirPath == '')
  98.       return null;
  99.  
  100.     var fileDb = FileIO.getFile(udfDbDirPath);
  101.     if (fileDb == null)
  102.       return null;
  103.  
  104.     fileDb.append("smFunctions.sqlite");
  105.     return fileDb;
  106.   },
  107.  
  108.   onSelectTab: function() {
  109.     var sId = $$("udfTabs").selectedItem.id;
  110.     switch(sId) {
  111.       case "udfTabNew":
  112.         break;
  113.       case "udfTabView":
  114.         break;
  115.     }
  116.   },
  117.  
  118.   //this function populates the menu in 'Simple Functions' tab
  119.   populateFuncMenuList: function(bAggregate) {
  120.     //of course, we cannot proceed without a db connection
  121.     if (this.dbFunc == null)
  122.       return;
  123.  
  124.     var sMlId = "udfFuncMenuList";
  125.     var sQuery = 'SELECT name FROM functions ORDER BY name';
  126.     if (bAggregate) {
  127.       sMlId = "udfAggFuncMenuList";
  128.       sQuery = 'SELECT name FROM aggregateFunctions ORDER BY name';
  129.     }
  130.  
  131.     var records = [];
  132.     try {
  133.       this.dbFunc.selectQuery(sQuery);
  134.       records = this.dbFunc.getRecords();
  135.     } catch (e) {
  136.       sm_log(e.message);
  137.       return false;
  138.     }
  139.  
  140.     var ml = $$(sMlId);
  141.     ml.removeAllItems();
  142.     var mi = ml.appendItem('--Select Function--', '---');
  143.     mi.setAttribute("disabled", "true");
  144.  
  145.     for (var i in records) {
  146.       ml.appendItem(records[i][0], records[i][0]);
  147.     }
  148.     ml.selectedIndex = 0;
  149.     return true;
  150.   },
  151.  
  152.   onSelectFuncName: function(bAggregate) {
  153.     var sMlId = "udfFuncMenuList";
  154.     if (bAggregate) {
  155.       sMlId = "udfAggFuncMenuList";
  156.     }
  157.  
  158.     var sVal = $$(sMlId).value;
  159.     switch (sVal) {
  160.       case '---':
  161.         break;
  162.       default:
  163.         if (bAggregate)
  164.           this.viewAggFunction();
  165.         else
  166.           this.viewFunction();
  167.     }
  168.   },
  169.  
  170.   saveFunction: function() {
  171.     var sName = $$("udfNewFuncName").value;
  172.     var iArg = $$("udfNewFuncArgLength").value;
  173.     var iEnabled = $$("udfNewFuncEnabled").checked?1:0;
  174.     var sBody = $$("udfNewFuncBody").value;
  175.  
  176.     var sOldName = $$("udfNewFuncName").getAttribute("oldName");
  177.  
  178.     try {
  179.       var sQDelete = "DELETE FROM functions WHERE name = " + SQLiteFn.quote(sOldName);
  180.       var sQInsert = "INSERT INTO functions (name, body, argLength, enabled) VALUES (" + SQLiteFn.quote(sName) + "," + SQLiteFn.quote(sBody) + "," + iArg + "," + iEnabled + ")";
  181.       this.dbFunc.executeSimpleSQLs([sQDelete, sQInsert]);
  182.     } catch (e) {
  183.       sm_log(e.message);
  184.       return false;
  185.     }
  186.     //populate menulist with all function names
  187.     this.populateFuncMenuList(false);
  188.     //notify the user
  189.     sm_notify('udfNotifyBox', 'New function added: ' + sName + '. Press "Reload Functions" button to access this function in SQL statements.', 'info');
  190.     this.viewFunction();
  191.     return true;
  192.   },
  193.  
  194.   saveAggFunction: function() {
  195.     var sName = $$("udfNewAggFuncName").value;
  196.     var iArg = $$("udfNewAggFuncArgLength").value;
  197.     var iEnabled = $$("udfNewAggFuncEnabled").checked?1:0;
  198.     var sOnStepBody = $$("udfNewAggFuncOnStepBody").value;
  199.     var sOnFinalBody = $$("udfNewAggFuncOnFinalBody").value;
  200.  
  201.     var sOldName = $$("udfNewAggFuncName").getAttribute("oldName");
  202.  
  203.     try {
  204.       var sQDelete = "DELETE FROM aggregateFunctions WHERE name = " + SQLiteFn.quote(sOldName);
  205.       var sQInsert = "INSERT INTO aggregateFunctions (name, argLength, onStepBody, onFinalBody, enabled) VALUES (" + SQLiteFn.quote(sName) + "," + iArg + "," + SQLiteFn.quote(sOnStepBody) + "," + SQLiteFn.quote(sOnFinalBody) + "," + iEnabled + ")";
  206.       this.dbFunc.executeSimpleSQLs([sQDelete, sQInsert]);
  207.     } catch (e) {
  208.       sm_log(e.message);
  209.       return false;
  210.     }
  211.     //populate menulist with all function names
  212.     this.populateFuncMenuList(true);
  213.     //notify the user
  214.     sm_notify('udfNotifyBox', 'New aggregate function added: ' + sName + '. Press "Reload Functions" button to access this function in SQL statements.', 'info');
  215.     this.viewAggFunction();
  216.     return true;
  217.   },
  218.  
  219.   reloadFunctions: function() {
  220.     SQLiteManager.createFunctions(false);
  221.   },
  222.  
  223.   addFunction: function() {
  224.     if (this.dbFunc == null)
  225.       return;
  226.  
  227.     $$("udfVbFuncEdit").hidden = false;
  228.     $$("udfVbFuncView").hidden = true;
  229.  
  230.     $$("udfNewFuncName").setAttribute("oldName", "");
  231.   },
  232.  
  233.   addAggFunction: function() {
  234.     if (this.dbFunc == null)
  235.       return;
  236.  
  237.     $$("udfVbAggFuncEdit").hidden = false;
  238.     $$("udfVbAggFuncView").hidden = true;
  239.  
  240.     $$("udfNewAggFuncName").setAttribute("oldName", "");
  241.   },
  242.  
  243.   cancelEditSimple: function() {
  244.     this.viewFunction();
  245.   },
  246.  
  247.   cancelEditAggregate: function() {
  248.     this.viewAggFunction();
  249.   },
  250.  
  251.   viewFunction: function() {
  252.     if (this.dbFunc == null)
  253.       return;
  254.  
  255.     $$("udfVbFuncEdit").hidden = true;
  256.     $$("udfVbFuncView").hidden = false;
  257.  
  258.     $$("udfBtnFuncEdit").setAttribute('disabled', true);
  259.     $$("udfBtnFuncDelete").setAttribute('disabled', true);
  260.  
  261.     $$("udfViewFuncHead").textContent = '';
  262.     $$("udfViewFuncBody").textContent = '';
  263.     $$("udfViewFuncTail").textContent = '';
  264.     var sFuncName = $$("udfFuncMenuList").value;
  265.     if (sFuncName == '---' || sFuncName == '@@@')
  266.       return false;
  267.  
  268.     var records = [];
  269.     try {
  270.       this.dbFunc.selectQuery("SELECT name, body, argLength, enabled FROM functions WHERE name = '" + sFuncName + "' ORDER BY name");
  271.       records = this.dbFunc.getRecords();
  272.     } catch (e) {
  273.       sm_log(e.message);
  274.       return false;
  275.     }
  276.  
  277.     var sTxt = [], sBody;
  278.     for (var i in records) {
  279.       sTxt.push('// name      = ' + records[i][0]);
  280.       sTxt.push('// argLength = ' + records[i][2]);
  281.       sTxt.push('// enabled   = ' + records[i][3]);
  282.       sTxt.push('function ' + records[i][0] + ' (aValues) {');
  283.       sBody = records[i][1];
  284.     }
  285.     $$("udfViewFuncHead").textContent = sTxt.join('\n');
  286.     $$("udfViewFuncBody").textContent = sBody;
  287.     $$("udfViewFuncTail").textContent = '}';
  288.  
  289.     $$("udfBtnFuncEdit").removeAttribute('disabled');
  290.     $$("udfBtnFuncDelete").removeAttribute('disabled');
  291.  
  292.     return true;
  293.   },
  294.  
  295.   viewAggFunction: function() {
  296.     if (this.dbFunc == null)
  297.       return;
  298.  
  299.     $$("udfVbAggFuncEdit").hidden = true;
  300.     $$("udfVbAggFuncView").hidden = false;
  301.  
  302.     $$("udfBtnAggFuncEdit").setAttribute('disabled', true);
  303.     $$("udfBtnAggFuncDelete").setAttribute('disabled', true);
  304.  
  305.     $$("udfViewAggFuncHead").textContent = '';
  306.     $$("udfViewAggFuncBody").textContent = '';
  307.     $$("udfViewAggFuncTail").textContent = '';
  308.     var sFuncName = $$("udfAggFuncMenuList").value;
  309.     if (sFuncName == '---' || sFuncName == '@@@')
  310.       return false;
  311.  
  312.     var records = [];
  313.     try {
  314.       this.dbFunc.selectQuery("SELECT name, onStepBody, onFinalBody, argLength, enabled FROM aggregateFunctions WHERE name = '" + sFuncName + "' ORDER BY name");
  315.       records = this.dbFunc.getRecords();
  316.     } catch (e) {
  317.       sm_log(e.message);
  318.       return false;
  319.     }
  320.  
  321.     var sTxt = [], sBody = [];
  322.     for (var i in records) {
  323.       sTxt.push('// name      = ' + records[i][0]);
  324.       sTxt.push('// argLength = ' + records[i][3]);
  325.       sTxt.push('// enabled   = ' + records[i][4]);
  326.  
  327.       sBody.push('var objectForAggregateFunction = {');
  328.       sBody.push('_store: [], //for storing values which can be used in onFinal()');
  329.       sBody.push('onStep: function (aValues) {//called for each row');
  330.       sBody.push(records[i][1]);
  331.       sBody.push('},');
  332.       sBody.push('onFinal: function () {//called at the end');
  333.       sBody.push(records[i][2]);
  334.       sBody.push('}');
  335.       sBody.push('}');
  336.     }
  337.     $$("udfViewAggFuncHead").textContent = sTxt.join('\n');
  338.     $$("udfViewAggFuncBody").textContent = sBody.join('\n');
  339.     $$("udfViewAggFuncTail").textContent = '';
  340.  
  341.     $$("udfBtnAggFuncEdit").removeAttribute('disabled');
  342.     $$("udfBtnAggFuncDelete").removeAttribute('disabled');
  343.  
  344.     return true;
  345.   },
  346.  
  347.   deleteFunction: function() {
  348.     if (this.dbFunc == null)
  349.       return false;
  350.  
  351.     var sFuncName = $$("udfFuncMenuList").value;
  352.     if (sFuncName == '---' || sFuncName == '@@@')
  353.       return false;
  354.  
  355.     var bAsk = sm_confirm("Confirm function deletion", "Do you really want to delete the function: " + sFuncName + "?");
  356.     if (!bAsk)
  357.       return false;
  358.  
  359.     try {
  360.       var sQuery = "DELETE FROM functions WHERE name = '" + sFuncName + "'";
  361.       this.dbFunc.executeSimpleSQLs([sQuery]);
  362.     } catch (e) {
  363.       sm_log(e.message);
  364.       return false;
  365.     }
  366.  
  367.     //populate menulist with all function names
  368.     this.populateFuncMenuList(false);
  369.     //notify the user
  370.     sm_notify('udfNotifyBox', 'Function deleted: ' + sFuncName + '. Press "Reload Functions" button.', 'info');
  371.     this.viewFunction();
  372.     return true;
  373.   },
  374.  
  375.   deleteAggFunction: function() {
  376.     if (this.dbFunc == null)
  377.       return false;
  378.  
  379.     var sFuncName = $$("udfAggFuncMenuList").value;
  380.     if (sFuncName == '---' || sFuncName == '@@@')
  381.       return false;
  382.  
  383.     var bAsk = sm_confirm("Confirm function deletion", "Do you really want to delete the function: " + sFuncName + "?");
  384.     if (!bAsk)
  385.       return false;
  386.  
  387.     try {
  388.       var sQuery = "DELETE FROM aggregateFunctions WHERE name = '" + sFuncName + "'";
  389.       this.dbFunc.executeSimpleSQLs([sQuery]);
  390.     } catch (e) {
  391.       sm_log(e.message);
  392.       return false;
  393.     }
  394.  
  395.     //populate menulist with all function names
  396.     this.populateFuncMenuList(true);
  397.     //notify the user
  398.     sm_notify('udfNotifyBox', 'Function deleted: ' + sFuncName + '. Press "Reload Functions" button.', 'info');
  399.     this.viewAggFunction();
  400.     return true;
  401.   },
  402.  
  403.   editFunction: function() {
  404.     if (this.dbFunc == null)
  405.       return false;
  406.  
  407.     var sFuncName = $$("udfFuncMenuList").value;
  408.     if (sFuncName == '---' || sFuncName == '@@@')
  409.       return false;
  410.  
  411.     $$("udfVbFuncEdit").hidden = false;
  412.     $$("udfVbFuncView").hidden = true;
  413.  
  414.     var records = [];
  415.     try {
  416.       this.dbFunc.selectQuery("SELECT name, body, argLength, enabled FROM functions WHERE name = '" + sFuncName + "' ORDER BY name");
  417.       records = this.dbFunc.getRecords();
  418.     } catch (e) {
  419.       sm_log(e.message);
  420.       return false;
  421.     }
  422.  
  423.     //fill in the correct entries in the controls
  424.     $$("udfNewFuncName").setAttribute("oldName", records[0][0]);
  425.     $$("udfNewFuncName").value = records[0][0];
  426.     $$("udfNewFuncArgLength").value = records[0][2];
  427.     $$("udfNewFuncEnabled").checked = records[0][3]?true:false;
  428.     $$("udfNewFuncBody").value = records[0][1];
  429.     
  430.     return true;
  431.   },
  432.  
  433.   editAggFunction: function() {
  434.     if (this.dbFunc == null)
  435.       return false;
  436.  
  437.     var sFuncName = $$("udfAggFuncMenuList").value;
  438.     if (sFuncName == '---' || sFuncName == '@@@')
  439.       return false;
  440.  
  441.     $$("udfVbAggFuncEdit").hidden = false;
  442.     $$("udfVbAggFuncView").hidden = true;
  443.  
  444.     var records = [];
  445.     try {
  446.       this.dbFunc.selectQuery("SELECT name, onStepBody, onFinalBody, argLength, enabled FROM aggregateFunctions WHERE name = '" + sFuncName + "' ORDER BY name");
  447.       records = this.dbFunc.getRecords();
  448.     } catch (e) {
  449.       sm_log(e.message);
  450.       return false;
  451.     }
  452.  
  453.     //fill in the correct entries in the controls
  454.     $$("udfNewAggFuncName").setAttribute("oldName", records[0][0]);
  455.     $$("udfNewAggFuncName").value = records[0][0];
  456.     $$("udfNewAggFuncArgLength").value = records[0][3];
  457.     $$("udfNewAggFuncEnabled").checked = records[0][4]?true:false;
  458.     $$("udfNewAggFuncOnStepBody").value = records[0][1];
  459.     $$("udfNewAggFuncOnFinalBody").value = records[0][2];
  460.     
  461.     return true;
  462.   },
  463.  
  464.   getFunctions: function() {
  465.     //of course, we cannot proceed without a db connection
  466.     if (this.dbFunc == null)
  467.       return;
  468.  
  469.     var allUdf = [];
  470.  
  471.     this.dbFunc.selectQuery('SELECT name, body, argLength FROM functions WHERE enabled = 1 AND aggregate = 0');
  472.     var records = this.dbFunc.getRecords();
  473.  
  474.     for (var i in records) {
  475.       try {
  476.         var func = new Function("aValues", records[i][1]);
  477.         var udf = {fName: records[i][0], fLength: records[i][2], onFunctionCall: func};
  478.         allUdf.push(udf);
  479.       } catch (e) {
  480.         sm_log("Failed to create function: " + records[i][0]);
  481.       }
  482.     }
  483.     return allUdf;
  484.   },
  485.  
  486.   getAggregateFunctions: function() {
  487.     //of course, we cannot proceed without a db connection
  488.     if (this.dbFunc == null)
  489.       return;
  490.  
  491.     var allUdf = [];
  492.  
  493.     this.dbFunc.selectQuery('SELECT name, argLength, onStepBody, onFinalBody FROM aggregateFunctions WHERE enabled = 1');
  494.     var records = this.dbFunc.getRecords();
  495.     for (var i in records) {
  496.       try {
  497.         var objAggFunc = {
  498.           _store: [],
  499.           onStep: new Function("aValues", records[i][2]),
  500.           onFinal: new Function(records[i][3])
  501.         };
  502.         var udf = {fName: records[i][0], fLength: records[i][1], objFunc: objAggFunc};
  503.         allUdf.push(udf);
  504.       } catch (e) {
  505.         sm_log("Failed to create function: " + records[i][0]);
  506.       }
  507.     }
  508.     return allUdf;
  509.   },
  510.  
  511.   showHelp: function(sArg) {
  512.     switch (sArg) {
  513.       case 'newFunctionArgLength':
  514.         smPrompt.alert(null, sm_getLStr("extName"), 'The number of arguments that the function will accept should be an integer.\n-1 means unlimited number of arguments.');
  515.         break;
  516.       case 'newFunctionBody':
  517.         smPrompt.alert(null, sm_getLStr("extName"), 'Write the function body without braces.\nThe argument to the function is "aValues" which can be used within the function body as in the example functions which you can see under the Simple Functions tab.');
  518.         break;
  519.       case 'newFunctionOnStepBody':
  520.         smPrompt.alert(null, sm_getLStr("extName"), 'Write the function body without braces.\nThe argument to the function is "aValues" which can be used within the function body as in the example functions which you can see under the Aggregate Functions tab.\nAny values you need to store for use in onFinal() can be stored in this._store which is initialized as an empty array');
  521.         break;
  522.       case 'newFunctionOnFinalBody':
  523.         smPrompt.alert(null, sm_getLStr("extName"), 'Write the function body without braces.\nThis function takes no arguments. See an example under the Aggregate Functions tab.\nYou can use this._store for computation in this function after you have stored values in it in the onStep() function.');
  524.         break;
  525.     }
  526.   },
  527. };
  528.  
  529.